package com.framework.camera;



import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.msgpack.MessagePack;
import org.msgpack.annotation.Message;
import org.msgpack.annotation.Optional;
import org.msgpack.packer.BufferPacker;
import org.msgpack.packer.Packer;
import org.msgpack.template.Template;
import org.msgpack.type.MapValue;
import org.msgpack.type.Value;
import org.msgpack.type.ValueFactory;
import org.msgpack.unpacker.BufferUnpacker;
import org.msgpack.unpacker.Unpacker;

import static org.msgpack.template.Templates.tMap;
import static org.msgpack.template.Templates.TByteArray;
import static org.msgpack.template.Templates.TString;
import static org.msgpack.template.Templates.TValue;
import static org.msgpack.template.Templates.tMap;
import android.text.format.Time;
import android.util.Log;



public class FrameBuilder {

	byte DAEMON        = 0x10;
	byte DAEMON_STATUS = 0x11;

	byte STORAGE                    = 0x20;
	//byte STORAGE_STATUS           = 0x21; // online/offline
	//byte 	//STORAGE_AVAILABLE      = 0x22; // disk available
	//byte 	//STORAGE_FRAMELIST      = 0x23; // framelist

	byte STORAGE_MOVIE_FRAME_ALL    = 0x30; // get movie all framelist
	byte STORAGE_MOVIE_FRAME_FIRST  = 0x31; // get movie first framelist
	byte STORAGE_MOVIE_FRAME_LAST   = 0x32; // get movie last framelist
	byte STORAGE_MOVIE_FRAME_RANGE  = 0x33; // get movie range frame
	byte STORAGE_AUDIO_FRAME_ALL    = 0x34; // get audio all framelist
	byte STORAGE_AUDIO_FRAME_FIRST  = 0x35; // get audio first framelist
	byte STORAGE_AUDIO_FRAME_LAST   = 0x36; // get audio last framelist
	byte STORAGE_AUDIO_FRAME_RANGE  = 0x37; // get audio range frame
	byte STORAGE_MOVIE_GETFRAME     = 0x40; // get movie frame object
	byte STORAGE_AUDIO_GETFRAME     = 0x41; // get audio frame object

	byte CAMERA                     = 0x40;
	byte CAMERA_STATUS              = 0x41;
	byte CAMERA_LIST                = 0x42;
	byte CAMERA_IPADDRESS           = 0x43;
	byte CAMERA_LOGS                = 0x44;
	byte CAMERA_SNAPSHOT            = 0x45;
	byte CAMERA_MOVIE_CAPTURE_START = 0x46;
	byte CAMERA_MOVIE_CAPTURE_STOP  = 0x47;
	byte CAMERA_AUDIO_CAPTURE_START = 0x48;
	byte CAMERA_AUDIO_CAPTURE_STOP  = 0x49;

	private int request_id = 0;


	// 通信フレームの組み立てクラス

	FrameBuilder(){
	    request_id  = 1;
//	    Logger = logging.getLogger('camfwlib.fb');
	}

	boolean SendRequest( Socket sock, int Type, Map<String, Object>Param){
		// [camfwlib] リクエスト送信
        MessagePack msgpack = new MessagePack();
        
		Time time = new Time("Asia/Tokyo");
		time.setToNow();

		String datetime = time.year + "/" + (time.month+1) + "/" + time.monthDay + " " + time.hour + ":" + time.minute + ":" + time.second;

        //
        // Serialization
        //
 
        OutputStream out = null;
		try {
			out = sock.getOutputStream();
		} catch (IOException e2) {
			// TODO 自動生成された catch ブロック
			e2.printStackTrace();
			return false;
		}
        Packer packer = msgpack.createPacker(out);
 
        // Serialize Map object
        Map<Object, Object> map_obj = new HashMap<Object, Object>();

        map_obj.put("header".getBytes(), "camfw req".getBytes());
        map_obj.put("time", datetime);
        map_obj.put("id", request_id);
        map_obj.put("type", Type);
        if(Param != null){
            map_obj.put("length", Param.size());
            map_obj.put("param", Param);
        }
        else{
        	map_obj.put("length", 0);
        }
        
        try {
			packer.write(map_obj);
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
			return false;
		} // Map object
        
        System.out.println(out);

		PrintWriter pw = null;
		pw = new PrintWriter(out,true);
        pw.print(out);       
        
        //
        // Deserialization
        //
 
//        byte[] bytes = out.toByteArray();
//        ByteArrayInputStream in = new ByteArrayInputStream(bytes);
//        Unpacker unpacker = msgpack.createUnpacker(in);
// 
//        // to Map object
//        try {
//			Map<String, String> dstMap = unpacker.read(mapTmpl);
//		} catch (IOException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
        
		return true;
	}

	Map<String, Value> RecieveResponse(Socket sock){
        Map<String, Value> dstMap = null;
        
		try {
    		MessagePack msgpack = new MessagePack();
    		Unpacker unpacker = msgpack.createUnpacker(sock.getInputStream());

    		dstMap = unpacker.read(tMap(TString, TValue));

//    		System.out.println(dstMap.get("param").asMapValue());  // 値をダンプ

		} catch (IOException e2) {
			// TODO 自動生成された catch ブロック
			e2.printStackTrace();
		}
		
		return dstMap;
	}

	Map<String, byte[]> ReceiveRequest(Socket sock){
        Template<Map<String, byte[]>> mapTmpl = tMap(TString, TByteArray);
        Map<String, byte[]> dstMap = null;

		try {
    		MessagePack msgpack = new MessagePack();
    		Unpacker unpacker = msgpack.createUnpacker(sock.getInputStream());

    		dstMap = unpacker.read(mapTmpl);

    		for(Value v : unpacker) {
    		    if(v.isMapValue()) { // 配列だったら...
    		        MapValue av = v.asMapValue();
    		        Map<Value,Value> list = av;  // ArrayValue は List<Value> を implements している！
    		        Value e = list.get(0);
    		    }

    		    System.out.println(v);  // 値をダンプ
    		}

		} catch (IOException e2) {
			// TODO 自動生成された catch ブロック
			e2.printStackTrace();
		}
		
		return dstMap;
	}
	
	void SendResponse( Socket sock, byte Type, String Param){

		//[camfwd] レスポンス送信

		Map<String, byte[]> map = new HashMap<String, byte[]>();
		Time time = new Time("Asia/Tokyo");
		time.setToNow();

		String datetime = time.year + "/" + (time.month+1) + "/" + time.monthDay + "/　" + time.hour + ":" + time.minute + ":" + time.second;
		try {
			map.put("header", "camfw req".getBytes());
			map.put("time", datetime.getBytes());
			map.put("id", Integer.toString(this.request_id).getBytes());
			map.put("type", Integer.toString(Type).getBytes());
		    if(Param != null){
		    	map.put("param", Param.getBytes());
		    	map.put("length", Integer.toString(Param.length()).getBytes());
		    }    
		    else{
		    	map.put("length", Integer.toString(0).getBytes());
		    }
	
			MessagePack msgpack = new MessagePack();
			BufferPacker pk = msgpack.createBufferPacker();

			Packer raw = pk.write(map);
			
			PrintWriter pw = new PrintWriter(sock.getOutputStream(),true);
			 
	        pw.println(raw);
	        
		} catch (IOException e) {
			// TODO 自動生成された catch ブロック
			e.printStackTrace();
		}
		
		return;
	}
}
